package com.ibeeking.found.upms.b.rest.service.impl;

import com.ibeeking.found.upms.b.rest.config.prop.UserConfigProp;
import com.ibeeking.found.upms.b.rest.service.IShopUserService;
import com.ibeeking.found.upms.b.rest.service.ITenantUserService;
import com.ibeeking.found.common.base.BaseDO;
import com.ibeeking.found.common.config.feign.GlobalClient;
import com.ibeeking.found.common.config.prop.FileOssProp;
import com.ibeeking.found.common.constants.DefaultPathConstant;
import com.ibeeking.found.common.constants.RoleConstant;
import com.ibeeking.found.common.entity.OperatorDTO;
import com.ibeeking.found.common.enums.PublishStatusEnum;
import com.ibeeking.found.common.enums.SexEnum;
import com.ibeeking.found.common.response.ResponseCodeEnum;
import com.ibeeking.found.common.utils.UrlUtils;
import com.ibeeking.found.common.utils.UserUtils;
import com.ibeeking.found.id.GenerateId;
import com.ibeeking.found.upms.api.common.param.ShopAdminInitParam;
import com.ibeeking.found.upms.api.common.param.ShopUserParam;
import com.ibeeking.found.upms.service.common.constants.RedisKeyConstant;
import com.ibeeking.found.upms.service.common.dos.ShopRoleDO;
import com.ibeeking.found.upms.service.common.dos.ShopUserRelationDO;
import com.ibeeking.found.upms.service.common.dos.ShopUserDO;
import com.ibeeking.found.upms.service.common.dos.ShopUserRoleDO;
import com.ibeeking.found.upms.service.common.po.ShopUserPagePO;
import com.ibeeking.found.upms.service.common.po.TenantUserPO;
import com.ibeeking.found.upms.service.common.query.ShopUserPageQuery;
import com.ibeeking.found.upms.service.common.vo.ShopUserPageVO;
import com.ibeeking.found.upms.service.common.vo.ShopUserVO;
import com.ibeeking.found.upms.service.mapper.ShopRoleMapper;
import com.ibeeking.found.upms.service.mapper.ShopUserRelationMapper;
import com.ibeeking.found.upms.service.mapper.ShopUserMapper;
import com.ibeeking.found.upms.service.mapper.ShopUserRoleMapper;
import com.ibeeking.nematos.exception.BusinessException;
import com.ibeeking.nematos.redis.utils.RedisUtils;
import com.ibeeking.nematos.utils.bean.BeanUtil;
import com.ibeeking.nematos.utils.data.Collections3;
import com.ibeeking.nematos.utils.data.StringUtils;
import com.ibeeking.nematos.utils.result.ResponseResult;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @ClassName ShopUserServiceImpl
 * @Description
 * @Author ibeeking
 * @Date 2021-04-15 9:01
 **/
@Service
public class ShopUserServiceImpl implements IShopUserService {

    private final static String INIT_SHOP_LOCK = "INIT_SHOP_LOCK:";
    private final static String INIT_SHOP = "INIT_SHOP:";

    @Resource
    private ShopUserMapper shopUserMapper;
    @Resource
    private ShopUserRelationMapper shopUserRelationMapper;
    @Resource
    private GlobalClient globalClient;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private UserConfigProp userConfigProp;
    @Resource
    private FileOssProp fileOssProp;
    @Resource
    private ShopUserRoleMapper shopUserRoleMapper;
    @Resource
    private ShopRoleMapper shopRoleMapper;
    @Resource
    private RedisUtils redisUtils;
    @Resource
    private ITenantUserService userServiceImpl;

    @Override
    public Page<ShopUserPageVO> pageList(Integer tenantId, ShopUserPageQuery query) {
        Page<ShopUserPagePO> page = shopUserMapper.queryList(new Page<>(query.getPageNum(), query.getPageSize()), tenantId, query);
        if (Collections3.isEmpty(page.getRecords())) {
            return new Page<>();
        }
        Page<ShopUserPageVO> result = BeanUtil.convertPage(page, ShopUserPageVO.class);
        List<Long> userIds = result.getRecords().stream().map(ShopUserPageVO::getCreateBy).distinct().collect(Collectors.toList());

        //查询员工角色
        List<ShopUserRoleDO> shopUserRoleDos = shopUserRoleMapper.selectList(new LambdaQueryWrapper<>(ShopUserRoleDO.class).eq(ShopUserRoleDO::getShopId, query.getShopId()).in(ShopUserRoleDO::getUserId, result.getRecords().stream().map(ShopUserPageVO::getId).distinct().collect(Collectors.toList())));
        Map<Long, StringBuffer> map = Collections3.emptyMap();
        if (!Collections3.isEmpty(shopUserRoleDos)) {
            List<ShopRoleDO> shopRoleDOS = shopRoleMapper.selectList(new LambdaQueryWrapper<>(ShopRoleDO.class).eq(ShopRoleDO::getPublishStatus, PublishStatusEnum.ENABLE.getValue())
                    .in(BaseDO::getId, shopUserRoleDos.stream().map(ShopUserRoleDO::getRoleId).distinct().collect(Collectors.toList()))
            );
            if (!Collections3.isEmpty(shopRoleDOS)) {
                map = new HashMap<>();
                Map<Long, String> roleNameMap = shopRoleDOS.stream().collect(Collectors.toMap(BaseDO::getId, ShopRoleDO::getName));
                for (ShopUserRoleDO userRoleDO : shopUserRoleDos) {
                    if (roleNameMap.containsKey(userRoleDO.getRoleId())) {
                        if (map.containsKey(userRoleDO.getUserId())) {
                            map.get(userRoleDO.getUserId()).append(roleNameMap.get(userRoleDO.getRoleId())).append(",");
                        } else {
                            map.put(userRoleDO.getUserId(), new StringBuffer(roleNameMap.get(userRoleDO.getRoleId())).append(","));
                        }
                    }
                }
            }
        }

        ResponseResult<List<OperatorDTO>> responseResult = globalClient.queryByUserIds(userIds);
        Map<Long, String> userMap = null;
        if (null != responseResult && !Collections3.isEmpty(responseResult.getData())) {
            userMap = responseResult.getData().parallelStream().collect(Collectors.toMap(OperatorDTO::getId, OperatorDTO::getName, (s, a) -> a));
        }
        for (ShopUserPageVO shopUserPageVO : result.getRecords()) {
            if (map.containsKey(shopUserPageVO.getId())) {
                shopUserPageVO.setRoleName(map.get(shopUserPageVO.getId()).toString());
            }
            if (StringUtils.isNotBlank(shopUserPageVO.getImage())) {
                shopUserPageVO.setImage(UrlUtils.addUrlDomainName(fileOssProp.getHost(), shopUserPageVO.getImage()));
            }
            if (!CollectionUtils.isEmpty(userMap) && userMap.containsKey(shopUserPageVO.getCreateBy())) {
                shopUserPageVO.setCreateByName(userMap.get(shopUserPageVO.getCreateBy()));
            }
            if(shopUserPageVO.getSex() != null ){
                shopUserPageVO.setSexName(SexEnum.getDescByCode(shopUserPageVO.getSex()));
            }
        }
        return result;
    }

    @Override
    public ShopUserVO view(Long id) {
        ShopUserDO shopUserDO = shopUserMapper.selectById(id);
        shopUserDO.setImage(UrlUtils.addUrlDomainName(fileOssProp.getHost(), shopUserDO.getImage()));
        return BeanUtil.convertBean(shopUserDO, ShopUserVO.class);
    }

    @Override
    public List<ShopUserDO> queryByMobile(String mobile) {
        ResponseResult<List<Integer>> responseResult = globalClient.queryTenantIds();
        if (null == responseResult || Collections3.isEmpty(responseResult.getData())) {
            throw new BusinessException(ResponseCodeEnum.TENANT_ID_NOT_EXIST.getMsg());
        }
        return shopUserMapper.selectByMobile(responseResult.getData(), mobile);
    }

    @Transactional(rollbackFor = {Exception.class})
    @Override
    public Boolean initShopAdmin(Integer tenantId, ShopAdminInitParam param) {
        if (param.getParams().stream().map(ShopUserParam::getShopId).distinct().collect(Collectors.toList()).size() != param.getParams().size()) {
            throw new BusinessException("请不要重复添加商户");
        }
        if (redisUtils.tryLock(INIT_SHOP_LOCK + tenantId)) {
            try {
                if (null != redisUtils.get(INIT_SHOP + tenantId)) {
                    throw new BusinessException("正在初始化商户员工中，请完成后再初始化新的商户");
                }
                redisUtils.set(INIT_SHOP + tenantId, tenantId, RedisKeyConstant.DAY);
            } finally {
                redisUtils.unlock(INIT_SHOP_LOCK + tenantId);
            }

        }
        try {
            List<ShopUserRoleDO> shopUserRoleDos = new ArrayList<>();
            //批量初始化员工
            batchInitUser(param, shopUserRoleDos);
            //批量初始化管理员
            batchInitUserRole(shopUserRoleDos);
            return true;
        } finally {
            redisUtils.expire(INIT_SHOP + tenantId, 0L);
        }
    }

    private Boolean batchInitUser(ShopAdminInitParam param, List<ShopUserRoleDO> shopUserRoleDos) {
        List<ShopUserDO> saves = new ArrayList<>();
        List<ShopUserRelationDO> shopUses = new ArrayList<>();
        //查询是否有租户端存在此手机号
        List<String> mobiles = param.getParams().stream().map(ShopUserParam::getMobile).collect(Collectors.toList());
        List<TenantUserPO> list = userServiceImpl.queryByMobiles(mobiles);
        if (!Collections3.isEmpty(list)) {
            throw new BusinessException(list.stream().map(TenantUserPO::getMobile).collect(Collectors.toList()).toString() + "已存在租户账号，不允许创建商户端账号");
        }
        //通过手机号查询是否存在
        List<ShopUserDO> shopUserDos = shopUserMapper.selectList(new LambdaQueryWrapper<>(ShopUserDO.class).in(ShopUserDO::getMobile, mobiles));
        if (!Collections3.isEmpty(shopUserDos)) {
            //批量更新状态
            ShopUserDO shopUserDO = new ShopUserDO();
            shopUserDO.setPublishStatus(PublishStatusEnum.ENABLE.getValue());
            shopUserDO.setModifyTime(LocalDateTime.now());
            shopUserMapper.update(shopUserDO, new LambdaUpdateWrapper<>(ShopUserDO.class).in(BaseDO::getId, shopUserDos.stream().map(BaseDO::getId).collect(Collectors.toList())));
        }
        Map<String, Long> userMap = shopUserDos.stream().collect(Collectors.toMap(ShopUserDO::getMobile, BaseDO::getId, (s, a) -> a));

        //删除已存在员工和商户关系
        for (ShopUserParam s : param.getParams()) {
            ShopUserDO shopUserDO = new ShopUserDO();
            if (userMap.containsKey(s.getMobile())) {
                shopUserDO.setId(userMap.get(s.getMobile()));
            } else {
                shopUserDO.setId(GenerateId.generateId());
            }
            shopUserDO.setUserCode(s.getMobile());
            shopUserDO.setName(s.getName());
            shopUserDO.setPassword(passwordEncoder.encode(userConfigProp.getInitialPwd()));
            shopUserDO.setImage(DefaultPathConstant.DEFAULT_USER_HEAD_IMAGE);
            shopUserDO.setMobile(s.getMobile());
            shopUserDO.setSex(SexEnum.UNKNOWN.getCode());
            shopUserDO.setPublishStatus(PublishStatusEnum.ENABLE.getValue());
            shopUserDO.setCreateBy(UserUtils.getUserId());
            shopUserDO.setCreateTime(LocalDateTime.now());
            //员工和店铺
            ShopUserRelationDO shopUserRelationDO = new ShopUserRelationDO();
            shopUserRelationDO.setShopId(s.getShopId());
            shopUserRelationDO.setCreateTime(LocalDateTime.now());
            shopUserRelationDO.setModifyTime(LocalDateTime.now());
            shopUserRelationDO.setId(shopUserDO.getId());
            if (userMap.containsKey(s.getMobile())) {
                //删除
                shopUserRelationMapper.delete(new LambdaUpdateWrapper<>(ShopUserRelationDO.class).eq(ShopUserRelationDO::getId, shopUserRelationDO.getId())
                        .eq(ShopUserRelationDO::getShopId, shopUserRelationDO.getShopId())
                );
            } else {
                saves.add(shopUserDO);
            }
            shopUserRelationDO.setLock(PublishStatusEnum.ENABLE.getValue());
            shopUserRelationDO.setJob(PublishStatusEnum.ENABLE.getValue());
            shopUses.add(shopUserRelationDO);

            //员工和角色
            ShopUserRoleDO shopUserRoleDO = new ShopUserRoleDO();
            shopUserRoleDO.setShopId(s.getShopId());
            if (userMap.containsKey(s.getMobile())) {
                shopUserRoleDO.setUserId(userMap.get(s.getMobile()));
            } else {
                shopUserRoleDO.setUserId(shopUserDO.getId());
            }

            shopUserRoleDos.add(shopUserRoleDO);
        }
        shopUserRelationMapper.insertBatchSomeColumn(shopUses);
        //批量新增员工
        if (!Collections3.isEmpty(saves)) {
            shopUserMapper.insertBatchSomeColumn(saves);
        }
        return true;
    }

    private Boolean batchInitUserRole(List<ShopUserRoleDO> shopUserRoleDos) {
        //删除现有管理员
        shopUserRoleMapper.delete(new LambdaUpdateWrapper<>(ShopUserRoleDO.class).in(ShopUserRoleDO::getShopId, shopUserRoleDos.stream().map(ShopUserRoleDO::getShopId).collect(Collectors.toList())));
        //查询超级管理员
        ShopRoleDO shopRoleDO = shopRoleMapper.selectOne(new LambdaQueryWrapper<>(ShopRoleDO.class)
                .eq(ShopRoleDO::getPublishStatus, PublishStatusEnum.ENABLE.getValue())
                .eq(ShopRoleDO::getCode, RoleConstant.ADMINISTRATOR)
        );
        if (null == shopRoleDO) {
            throw new BusinessException("请先配置商户超级管理员后再初始化");
        }
        for (ShopUserRoleDO shopUserRoleDO : shopUserRoleDos) {
            shopUserRoleDO.setRoleId(shopRoleDO.getId());

        }
        return shopUserRoleMapper.insertBatchSomeColumn(shopUserRoleDos) > 0;
    }
}
